/*
 *
 *  *  Copyright (c), utrix (idea110@163.com).
 *  *  <p>
 *  *  Licensed under the GNU Lesser General Public License 3.0 (the "License");
 *  *  you may not use this file except in compliance with the License.
 *  *  You may obtain a copy of the License at
 *  *  <p>
 *  * https://www.gnu.org/licenses/lgpl.html
 *  *  <p>
 *  * Unless required by applicable law or agreed to in writing, software
 *  * distributed under the License is distributed on an "AS IS" BASIS,
 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  * See the License for the specific language governing permissions and
 *  * limitations under the License.
 *
 */

package priv.utrix.micro.utils;

import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * redis全局工具类
 *
 * @author utrix
 * @since 2020/10/14 15:09
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RedisUtil {

    final RedisTemplate<String, Object> redisTemplate;
    final StringRedisTemplate stringRedisTemplate;

    /**
     * 根据key获取对应的value
     *
     * @param key 键
     * @return java.lang.Object
     * @since 2020/10/14 15:15
     */
    public Object get(Object key) {
        checkNotNull(key);
        return redisTemplate.opsForValue().get(key);
    }

    /**
     * 获取指定key的过期时间
     *
     * @param key key值
     * @return java.lang.Long 单位: 秒
     */
    public Long getExpire(Object key) {

        checkNotNull(key);
        return redisTemplate.opsForValue().getOperations().getExpire(key.toString());
    }

    /**
     * 向redis中赋值字符串，键值对
     *
     * @param key   键
     * @param value 值
     * @since 2020/10/14 15:14
     */
    public void set(String key, Object value) {
        checkNotNull(key);
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 设置键值，并设置过时时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过时时间，单位s
     * @since 2020/10/14 15:23
     */
    public void set(String key, Object value, long timeout) {
        checkNotNull(key);
        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 向redis中赋值字符串，键值对
     * <p>如果不存在，则新增；存在则不做更改</p>
     *
     * @param key   键
     * @param value 值
     * @since 2020/10/14 15:14
     */
    public void setIfAbsent(String key, Object value) {
        checkNotNull(key);
        redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    /**
     * 设置键值，并设置过时时间
     * <p>如果不存在，则新增；存在则不做更改</p>
     *
     * @param key     键
     * @param value   值
     * @param timeout 过时时间，单位s
     * @since 2020/10/14 15:23
     */
    public void setIfAbsent(String key, Object value, long timeout) {
        checkNotNull(key);
        redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置键值，并设置过时时间
     * <p>如果不存在，则新增；存在则不做更改</p>
     *
     * @param key      键
     * @param value    值
     * @param timeout  过时时间
     * @param timeUnit 时间单位
     * @since 2020/10/14 15:23
     */
    public void setIfAbsent(String key, Object value, long timeout, TimeUnit timeUnit) {
        checkNotNull(key);
        redisTemplate.opsForValue().setIfAbsent(key, value, timeout, timeUnit);
    }

    /**
     * 根据key获取对应的value, 字符串
     *
     * @param key 键
     * @return java.lang.String
     * @since 2020/10/14 15:15
     */
    public String strGet(String key) {
        checkNotNull(key);
        return stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * 向redis中赋值字符串，键值对
     *
     * @param key   键
     * @param value 值
     * @since 2020/10/14 15:14
     */
    public void strSet(String key, String value) {
        checkNotNull(key);
        stringRedisTemplate.opsForValue().set(key, value);
    }

    /**
     * 向redis中赋值字符串，键值对, 并设置过时时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过时时间，单位毫秒
     * @since 2020/10/14 15:28
     */
    public void strMilliSet(String key, String value, long timeout) {
        checkNotNull(key);
        stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.MILLISECONDS);
    }

    /**
     * 向redis中赋值字符串，键值对, 并设置过时时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 过时时间，单位秒
     * @since 2020/10/14 15:28
     */
    public void strSecondsSet(String key, String value, long timeout) {
        checkNotNull(key);
        stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 向redis中赋值字符串，键值对
     * <p>如果不存在，则新增；存在则不做更改</p>
     *
     * @param key   键
     * @param value 值
     * @since 2020/10/14 15:14
     */
    public void strSetIfAbsent(String key, String value) {
        checkNotNull(key);
        stringRedisTemplate.opsForValue().setIfAbsent(key, value);
    }

    /**
     * 向redis中赋值字符串，键值对, 并设置过时时间
     * <p>如果不存在，则新增；存在则不做更改</p>
     *
     * @param key     键
     * @param value   值
     * @param timeout 过时时间，单位秒
     * @since 2020/10/14 15:28
     */
    public void strSetIfAbsent(String key, String value, long timeout) {
        checkNotNull(key);
        stringRedisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 清楚所有值
     *
     * @since 2020/10/14 15:56
     */
    public void clear() {
        redisTemplate.execute((RedisCallback<Object>) conn -> {
            conn.flushDb();
            return null;
        });
    }

    /**
     * 清楚所有值
     *
     * @since 2020/10/14 15:56
     */
    public void strClear() {
        stringRedisTemplate.execute((RedisCallback<Object>) conn -> {
            conn.flushDb();
            return null;
        });
    }

    /**
     * 根据键删除
     *
     * @param key 键
     * @since 2020/10/14 15:57
     */
    public void remove(String key) {
        checkNotNull(key);
        try {
            redisTemplate.delete(key);
            log.debug("Remove cached query result from redis");
        } catch (Throwable t) {
            log.error("Redis remove failed", t);
        }
    }

    /**
     * 判断值是否存在
     *
     * @param key 键
     * @return java.lang.Boolean
     * @since 2020/10/14 16:01
     */
    public Boolean isKey(String key) {
        if (StrUtil.isBlank(key)) return false;

        return redisTemplate.hasKey(key);
    }

}
